/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.engine.impl.cmd;

import com.je.bpm.core.model.Activity;
import com.je.bpm.core.model.BpmnModel;
import com.je.bpm.core.model.MultiInstanceLoopCharacteristics;
import com.je.bpm.core.model.task.KaiteCounterSignUserTask;
import com.je.bpm.engine.ActivitiException;
import com.je.bpm.engine.delegate.DelegateExecution;
import com.je.bpm.engine.impl.bpmn.behavior.AbstractBpmnActivityBehavior;
import com.je.bpm.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import com.je.bpm.engine.impl.bpmn.behavior.ParallelMultiInstanceBehavior;
import com.je.bpm.engine.impl.history.HistoryManager;
import com.je.bpm.engine.impl.interceptor.CommandContext;
import com.je.bpm.engine.impl.persistence.entity.ExecutionEntity;
import com.je.bpm.engine.impl.persistence.entity.ExecutionEntityManager;
import com.je.bpm.engine.impl.persistence.entity.TaskEntity;
import com.je.bpm.engine.impl.util.ProcessDefinitionUtil;

import java.util.List;

/**
 * 加签任务命令
 */
public class CountersignedAddSignatureCmd extends AbstractCompleteTaskCmd {

    private String taskId;

    private String assignee;

    public CountersignedAddSignatureCmd(String assignee, String taskId) {
        super(taskId, null, null);
        this.taskId = taskId;
        this.assignee = assignee;
    }

    public String getTaskId() {
        return taskId;
    }

    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    public String getAssignee() {
        return assignee;
    }

    public void setAssignee(String assignee) {
        this.assignee = assignee;
    }

    @Override
    protected Void execute(CommandContext commandContext, TaskEntity task) {
        ExecutionEntity currentExecutionEntity = task.getExecution();

        DelegateExecution rootExecution = getMultiInstanceRootExecution(task.getExecution());

        List<String> users = getListVariable(rootExecution, MultiInstanceActivityBehavior.PROCESSING_USERS_INFO);
        if (users.contains(assignee)) {
            throw new ActivitiException("已存在此人，无法加签！");
        }
        users.add(assignee);
        //判断当前执行实例的节点是否是多实例节点
        BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(task.getProcessDefinitionId());
        Activity miActivityElement = (Activity) bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        MultiInstanceLoopCharacteristics loopCharacteristics = miActivityElement.getLoopCharacteristics();
        if (loopCharacteristics == null) {
            throw new ActivitiException("此节点不是多实例节点");
        }

        //获取设置变量
        Integer nrOfInstances = (Integer) rootExecution.getVariableLocal(MultiInstanceActivityBehavior.NUMBER_OF_INSTANCES);
        rootExecution.setVariableLocal(MultiInstanceActivityBehavior.NUMBER_OF_INSTANCES, nrOfInstances + 1);
        rootExecution.setVariable(MultiInstanceActivityBehavior.PROCESSING_USERS_INFO, users);
        for (DelegateExecution execution : rootExecution.getExecutions()) {
            ExecutionEntity executionEntity = (ExecutionEntity) execution;
            List<TaskEntity> list = executionEntity.getTasks();
            for (TaskEntity task1 : list) {
                task1.setVariableLocal(MultiInstanceActivityBehavior.PROCESSING_USERS_INFO, users);
            }
        }

        //判断是否是并行多实例
        if (!loopCharacteristics.isSequential()) {
            Integer nrOfActiveInstances = (Integer) rootExecution.getVariableLocal(MultiInstanceActivityBehavior.NUMBER_OF_ACTIVE_INSTANCES);
            rootExecution.setVariableLocal(MultiInstanceActivityBehavior.NUMBER_OF_ACTIVE_INSTANCES, nrOfActiveInstances + 1);
            ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
            //创建新的子实例
            ExecutionEntity childExecution = executionEntityManager.createChildExecution((ExecutionEntity) rootExecution);
            //获取并为新的执行实例设置当前活动节点
            KaiteCounterSignUserTask currentFlowElement = (KaiteCounterSignUserTask) currentExecutionEntity.getCurrentFlowElement();
            //设置处理人
            currentFlowElement.setAssignee(assignee);
            childExecution.setVariableLocal(MultiInstanceActivityBehavior.EACH_LOOP_USER, assignee);
            int loopCounter = 0;
            for (DelegateExecution execution : rootExecution.getExecutions()) {
                if (execution.getVariableLocal("loopCounter") == null) {
                    continue;
                }
                if (loopCounter < (int) execution.getVariableLocal("loopCounter")) {
                    loopCounter = (int) execution.getVariableLocal("loopCounter");
                }
            }
            childExecution.setVariableLocal("loopCounter", loopCounter);
            childExecution.setCurrentFlowElement(currentFlowElement);
            //通知活动开始
            HistoryManager historyManager = commandContext.getHistoryManager();
            historyManager.recordActivityStart(childExecution);
            //获取处理行为类
            ParallelMultiInstanceBehavior prallelMultiInstanceBehavior = (ParallelMultiInstanceBehavior) miActivityElement.getBehavior();
            AbstractBpmnActivityBehavior innerActivityBehavior = prallelMultiInstanceBehavior.getInnerActivityBehavior();
            //执行
            innerActivityBehavior.execute(childExecution);
        }
        return null;
    }

    protected DelegateExecution getMultiInstanceRootExecution(DelegateExecution executionEntity) {
        DelegateExecution multiInstanceRootExecution = null;
        DelegateExecution currentExecution = executionEntity;
        while (currentExecution != null && multiInstanceRootExecution == null && currentExecution.getParent() != null) {
            if (currentExecution.isMultiInstanceRoot()) {
                multiInstanceRootExecution = currentExecution;
            } else {
                currentExecution = currentExecution.getParent();
            }
        }
        return multiInstanceRootExecution;
    }

}

